package DEEPERsource.DEEPERsource.source.corpus.ppi;

import java.io.File;
import java.io.FileInputStream;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import preprocessing.Preprocessor;

import corpus.CorpusBuilder;
import corpus.Sentence;
import corpus.Text;
import deeper.Direction;
import deeper.Interaction;
import deeper.InteractionType;
import deeper.Protein;

/**
 * Factory is responsible for building XML corpus from the source.
 * Sentences in the obtained corpus should contain proteins list and
 * interactions list (if avaliable)
 *
 */
public class CorpusFactory{
		
	public boolean suppressDirection = false;
	/**
	 * Builds a corpus using the PPI-conversion XML file
	 * @param file
	 * @return
	 */
	public Text getCorpusFromPPIXML(String file, Preprocessor prep){
		XMLParser handler = new XMLParser();
		handler.prep = prep;
		handler.suppressDirection = suppressDirection;
		SAXParserFactory factory = SAXParserFactory.newInstance();
		try{
			SAXParser saxParser = factory.newSAXParser();
			saxParser.parse(new FileInputStream(new File(file)), handler);
		} catch (Throwable t) {
			t.printStackTrace();
		}
		return handler.builder.getCorpus();
	}
	
	/**
	 * Stub for obtaining LLL corpus. PPI version is not suitable
	 * because it does not contains proteins, that do not take part
	 * in interactions
	 * @param file
	 * @return
	 */
	public Text getLLLCorpus(String file){
		return null;
	}
	
	/**
	 * Stub for a test corpus (containing protein tags only).
	 * Note: parameter is text itself, not file, since it 
	 * is intended for interactive use.
	 * @param file
	 * @return
	 */
	public Text getTestCorpus(String text){
		return null;
	}
}

class XMLParser extends DefaultHandler {
	private static Log _log = LogFactory.getLog(XMLParser.class);
	
	CorpusBuilder builder;
	//corpus could be started not only from <corpus> tag, but alsi directly
	//from <abstract> or <sentence>. May be abundant.
	boolean firstTag;
	boolean suppressDirection;
	String abstId;
	Sentence sentence;
	Preprocessor prep;
	String corpusName;
	
	public void startDocument() throws SAXException {
		builder = new CorpusBuilder();
		firstTag = true;
	}

	public void endDocument() throws SAXException {
				
	}
	
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		String id = attributes.getValue("id");
		String origId = attributes.getValue("origId");
		String seqId = attributes.getValue("seqId");
		if(origId==null)
			origId = "";
		if(qName.equals("corpus")){
			if(firstTag){
				corpusName = attributes.getValue("source");
				builder.initCorpus(corpusName);
				firstTag = false;
			}else{
				throw new SAXException("<corpus> could be top-level tag only. seqId="+seqId);
			}
		}else if(qName.equals("document")){
			abstId = id;
			if(firstTag){
				builder.initAbstract(abstId, origId);
				firstTag = false;
			}else{
				builder.addAbstract(abstId, origId);
			}
		}else if(qName.equals("sentence")){
			if(firstTag){
				throw new SAXException("<sentence> could not be top-level tag. seqId="+seqId);
			}
			String sent = attributes.getValue("text");
			sentence = (Sentence)builder.addSentence(sent, id, origId, abstId);
		}else if(qName.equals("entity")){
			if(firstTag){
				throw new SAXException("<entity> could not be top-level tag. seqId="+seqId);
			}
			Protein p = new Protein();
			if(corpusName.equals("LLLTest"))
				p.name = attributes.getValue("canonicalForm");
			else
				p.name = attributes.getValue("text");
			p.type = attributes.getValue("type");
			String[] offsets = attributes.getValue("charOffset").split(",");
			p.startOffset = new int[offsets.length];
			p.endOffset = new int[offsets.length];
			int i = 0;
			for(String off : offsets){
				String[] offset = off.split("-");
				p.startOffset[i] = Integer.parseInt(offset[0]); 
				p.endOffset[i] = Integer.parseInt(offset[1]);
				i++;
			}			
			p.id = id;
			sentence.addProtein(p);
		}else if(qName.equals("interaction")){
			if(firstTag){
				throw new SAXException("<interaction> could not be top-level tag. seqId="+seqId);
			}
			Interaction i = new Interaction();
			i.id = id;
			i.sentId = sentence.id();
			i.origSentId = sentence.originalId();
			i.type = attributes.getValue("type");
			i.p1 = sentence.getProtein(attributes.getValue("e1"));
			i.p2 = sentence.getProtein(attributes.getValue("e2"));
			if(suppressDirection)
				i.status = InteractionType.REAL;
			else{
				if(Boolean.parseBoolean(attributes.getValue("directed"))){
					if(i.p1.compareTo(i.p2)>0){
						i.status = InteractionType.REALINVERSE;
					}else{
						i.status = InteractionType.REALSTRAIGHT;
					}
				}else{
					i.status = InteractionType.REAL;
				}
			}
			sentence.addInteraction(i);
		}
	}
	
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if(qName.equals("sentence")){
			_log.debug(sentence.text);
			sentence.populateInteractions(prep);
		}
	}
}
